/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = cups_request.c                                                */
/*  NOTE      = cups request解析                                              */
/*  DATE      = 2015/03/18 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>

#include "cups_core.h"
#include "cups_comm.h"
#include "cups_request.h"

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  上报请求信息
*  ARGS     :  p_st_conn(入力链接信息)
*           :  p_st_private(私有session数据)
*           :  p_st_hash_report(保存Frreport_data)
*  RTN      :  APM_L7_ANALYZE_FAIL      (FAIL)
*              APM_L7_ANALYZE_SUCC      (SUCC)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __cups_report_resp(Conntrack *p_st_conn
                                  , Frhash_header *p_st_hash_report
                                  , L7session_cups_private *p_st_private)
{
    int i_ret = FR_SUCC;
    unsigned long ul_server_time_us = 0;
    Frlist_node *p_st_node = NULL;
    cups_field_info *p_st_field = NULL;
    Frreport_data *p_st_report_data = NULL;
    Frreport_body_data *p_st_sess_body = NULL;
    L7_req_cups *p_st_req = p_st_private->p_st_req;
    L7_resp_cups *p_st_resp = p_st_private->p_st_resp;
    L7_fragment_cups *p_st_fragment = p_st_private->p_st_fragment;
    char arr_key[256] = {0};
    char *p_channel = NULL;
    char *p_type_name = NULL;
    char *p_utf8_str = NULL;
    unsigned int ui_utf8_len = 0;
    unsigned int ui_key_len = sizeof(arr_key) - strlen(CUPS_REPORT_KEY_REQ) + 1;
    char *p_key = arr_key;
    snprintf(p_key, 256, "%s.", CUPS_REPORT_KEY_REQ);
    p_key += strlen(CUPS_REPORT_KEY_REQ) + 1;
    unsigned int ui_digits = 0;

    Conntrack *p_st_conn_bef = p_st_conn;
    L7_session *p_st_session_bef = NULL;
    L7session_cups_private *p_st_private_bef = NULL;

    /* request异步 */
    if (p_st_req == NULL)
    {
        p_st_conn_bef = frexpect2_get(g_p_apm_context, p_st_fragment->arr_src_id, p_st_fragment->arr_dest_id);
        if (p_st_conn_bef)
        {
            frexpect2_put(g_p_apm_context, p_st_fragment->arr_dest_id, p_st_fragment->arr_src_id);
            p_st_session_bef = frct_get_session(p_st_conn_bef);
            if (p_st_session_bef)
            {
                p_st_private_bef = (L7session_cups_private *)p_st_session_bef->p_session_private;
            }
        }

        if (p_st_private_bef == NULL || p_st_private_bef->p_st_req == NULL)
        {
            frdbg("Get before sesseion failed!\n");
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_req = p_st_private_bef->p_st_req;
    }

    cpus_get_digits(p_st_req->ui_currency, &ui_digits);

    /* 创建report body */
    p_st_sess_body = frreport_body_new_l7(p_st_conn_bef);
    if (p_st_sess_body == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 追加connection相关信息 */
    i_ret = frreport_body_l7_add_connInfo(p_st_sess_body, p_st_conn_bef);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add title */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , APM_REPORT_KEY_TRANS_TITLE
                                    , p_st_req->arr_msg_type);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add sequence id */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_ID
                                      , p_st_req->ul_req_sequence);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add isResponseRequired */
    i_ret = frreport_body_l7_add_int(p_st_sess_body
                                    , APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add request start time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_REQ_START_TIMESTAMP
                                        , &p_st_req->st_start_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add request end time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_REQ_END_TIMESTAMP
                                        , &p_st_req->st_end_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add send time */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_SEND_TIME_US
                                      , p_st_req->ul_send_time_us);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add send data bytes */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_DATA_BYTES
                                      , p_st_req->ul_request_bytes);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add message type */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_REQ_MSG_TP
                                    , p_st_req->arr_msg_type);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add trans info */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_REQ_TRANS
                                    , p_st_req->arr_trans_info);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add dest id */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_REQ_DEST_ID
                                    , p_st_req->arr_dest_id);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add src id */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_REQ_SRC_ID
                                    , p_st_req->arr_src_id);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    p_st_node = FRLIST_FIRST_NODE(&p_st_req->st_param);
    while (p_st_node)
    {
        p_st_field = (cups_field_info *)FRLIST_GET_NODE_DATA(p_st_node);
        /* 做成key */
        snprintf(p_key, ui_key_len, "%s"
                , cups_ret_value(p_st_field->ui_field_index - 1));
        /* 根据域号确定上报数据 */
        switch (p_st_field->ui_field_index)
        {
            case 3:
                i_ret = cups_get_type_name(p_st_field->p_field_value, &p_type_name);
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }

                i_ret = frreport_body_l7_add_str(p_st_sess_body, CUPS_REPORT_KEY_CONN_TYPE_CODE
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frfree(p_type_name);
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }

                i_ret = frreport_body_l7_add_str(p_st_sess_body, CUPS_REPORT_KEY_CONN_TYPE_NAME, p_type_name);
                frfree(p_type_name);
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 4:
            case 5:
            case 6:
                i_ret = cups_get_currency(&p_st_field->p_field_value, ui_digits);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 28:
                i_ret = cups_get_currency2(&p_st_field->p_field_value, ui_digits);
                if (i_ret != APM_L7_ANALYZE_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 38:
            case 41:
                frrtrim(p_st_field->p_field_value);
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 60:
                i_ret = cups_get_channel(p_st_field->p_field_value, &p_channel);
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                i_ret = frreport_body_l7_add_str(p_st_sess_body, CUPS_REPORT_KEY_CONN_CHANNEL, p_channel);
                frfree(p_channel);
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }

                /* add value */
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 11:
                i_ret = frreport_body_l7_add_str(p_st_sess_body, APM_REPORT_KEY_TRANS_CODE
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                /* add value */
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            case 43:
                frrtrim(p_st_field->p_field_value);
            case 61:
            case 62:
                if (p_st_field->p_field_value)
                {
                    /* 将参数信息转成UTF-8 */
                    i_ret = iconv_to_utf8(p_st_field->p_field_value
                                         , strlen(p_st_field->p_field_value)
                                         , "gb18030", &p_utf8_str, &ui_utf8_len);
                    if (i_ret == 2)
                    {
                        frreport_body_free(&p_st_sess_body);
                        return APM_L7_ANALYZE_FAIL;
                    }
                }
                else
                {
                    p_utf8_str = NULL;
                }
                /* add value */
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_utf8_str ? p_utf8_str : "");
                cups_free(&p_utf8_str);
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;

            default:
                /* add value */
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->p_field_value ? p_st_field->p_field_value : "");
                if (i_ret != FR_SUCC)
                {
                    frreport_body_free(&p_st_sess_body);
                    return APM_L7_ANALYZE_FAIL;
                }
                break;
        }

        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    /* add response info */
    /* add response start time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_RESP_START_TIMESTAMP
                                        , &p_st_fragment->st_start_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add response end time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_RESP_END_TIMESTAMP
                                        , &p_st_fragment->st_end_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add send time */
    ul_server_time_us = cups_get_interval_time(&p_st_req->st_end_timestamp
                                              , &p_st_fragment->st_start_timestamp);
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_RESP_SERVER_TIME_US
                                      , ul_server_time_us);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add send time */
    ul_server_time_us = cups_get_interval_time(&p_st_fragment->st_start_timestamp
                                              , &p_st_fragment->st_end_timestamp);
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US
                                      , ul_server_time_us);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add send data bytes */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_RESP_DATA_BYTES
                                      , p_st_fragment->ui_packet_len);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add message type */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_RESP_MSG_TP
                                    , p_st_fragment->arr_msg_type);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

     /* add trans info */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_RESP_TRANS
                                    , p_st_fragment->arr_trans_info);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add dest id */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_RESP_DEST_ID
                                    , p_st_fragment->arr_dest_id);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add src id */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , CUPS_REPORT_KEY_RESP_SRC_ID
                                    , p_st_fragment->arr_src_id);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add response code */
    i_ret = frreport_body_l7_add_long(p_st_sess_body
                                     , APM_REPORT_KEY_RESP_CODE
                                     , p_st_fragment->ui_rej_code);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return FR_FAIL;
    }

    /* add response code string */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                     , APM_REPORT_KEY_RESP_CODE_STRING
                                     , p_st_resp->arr_ret_code);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return FR_FAIL;
    }

    /* add response error message */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                    , APM_REPORT_KEY_RESP_ERR_MSG
                                    , p_st_resp->p_error_msg ? p_st_resp->p_error_msg : "");
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return FR_FAIL;
    }

    /* 创建report data header */
    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
    if (p_st_report_data == NULL)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add body into header */
    i_ret = frreport_data_add_body(p_st_report_data, p_st_sess_body);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        frreport_data_free(&p_st_report_data);
        return APM_L7_ANALYZE_FAIL;
    }

    /* 上报request数据 */
    i_ret = frreport_data_hash(p_st_hash_report, p_st_report_data);
    if (i_ret != FR_SUCC)
    {
        frreport_data_free(&p_st_report_data);
        return APM_L7_ANALYZE_FAIL;
    }

    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
}

/*******************************************************************************
*  FUNC     :  解析request
*  ARGS     :  p_st_conn (入力链接信息)
*           :  p_st_hash_report(Frreport_data)
*           :  p_st_private(cups交易私有数据)
*  RTN      :  参照module.h
*  NOTE     :
*******************************************************************************/
int cups_parse_response(Conntrack *p_st_conn
                        , L7session_cups_private *p_st_private
                        , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_resp_cups *p_st_resp = NULL;
    L7_fragment_cups *p_st_fragment = p_st_private->p_st_fragment;

    p_st_resp = (L7_resp_cups *)frmalloc(sizeof(L7_resp_cups));
    if (p_st_resp == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    memset(p_st_resp, 0x0, sizeof(L7_resp_cups));
    p_st_private->p_st_resp = p_st_resp;

    p_st_resp->p_error_msg = cups_error_msg(p_st_fragment->ui_rej_code);
    snprintf(p_st_resp->arr_ret_code, sizeof(p_st_resp->arr_ret_code)
            , "%05d", p_st_fragment->ui_rej_code);

    i_ret = __cups_report_resp(p_st_conn, p_st_hash_report, p_st_private);
    return i_ret;
}
